package com.open.system.dispatch.impl;


import com.open.base.model.Menu;
import com.open.base.model.Role;
import com.open.common.constants.Constants;
import com.open.system.dispatch.IMenuDispatch;
import com.open.system.model.RoleMenu;
import com.open.system.model.dto.MenuDto;
import com.open.system.model.vo.MetaVo;
import com.open.system.model.vo.RouterVo;
import com.open.system.service.IMenuService;
import com.open.system.service.IRoleMenuService;
import com.open.system.service.IRoleService;
import com.open.common.utils.CollectionUtils;
import com.open.common.utils.ThrowUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单信息
 *
 * @author 大树03
 * @date 2025-02-02 01:03
 */
@Component(value = "menuDispatch")
@Slf4j
public class MenuDispatchImpl implements IMenuDispatch {
    @Autowired
    private IRoleMenuService roleMenuService;

    @Autowired
    private IRoleService roleService;

    private IMenuService menuService;

    @Autowired
    public void setMenuService(IMenuService menuService) {
        this.menuService = menuService;
    }

    //缓存Menu
    private Map<Long, Menu> menuMap;

    @Override
    public Boolean save(Menu model) {
        String permissionVal = model.getPermissionVal();
        if (!StringUtils.isEmpty(permissionVal)) {
            List<Menu> menus = menuService.findByModel(new Menu(permissionVal));
            ThrowUtils.throwIf(CollectionUtils.isNotEmpty(menus), "权限串值不能重复");
        }
        return menuService.save(model);
    }

    @Override
    public Boolean update(Menu model) {
        String permissionVal = model.getPermissionVal();
        //权限串值不能重复，排除当前菜单
        menuService.findByModel(new Menu(permissionVal)).stream().filter(menuItem -> !StringUtils.isEmpty(menuItem.getPermissionVal()))
                .forEach(item -> {
                    if (item.getId().equals(model.getId())) {
                        return;
                    }
                    ThrowUtils.throwIf(item.getPermissionVal().equals(permissionVal), "权限串值不能重复");
                });

        //菜单状态修改
        Menu currentMenu = menuService.findByPk(model.getId());

        assert currentMenu != null;
        if (currentMenu.getStatus().equals(model.getStatus())) {
            return menuService.update(model);
        }

        // 更新子节点状态
        List<Menu> childMenus = findByModel(new Menu(model.getId()));
        if (CollectionUtils.isNotEmpty(childMenus)) {
            childMenus.stream().filter(item -> item.getStatus() != 2).forEach(item -> {
                item.setStatus(model.getStatus());
                update(item);
            });
        }

        return menuService.update(model);
    }

    @Override
    public List<Menu> findTree(Menu menu) {
        Map<String, Object> map = this.initMapParam(menu);
        map.put("sortBySql", "order by parent_id, order_num");
        List<Menu> menus = menuService.findByModel(map);
        return this.buildTree(menus);
    }

    @Override
    public Menu findByPk(Long pk) {
        return menuService.findByPk(pk);
    }

    @Override
    public List<Menu> findByModel(Menu model) {
        return menuService.findByModel(model);
    }

    @Override
    public Boolean remove(Long pk) {
        List<Menu> list = findByModel(new Menu(pk));
        //递归删除子节点
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(item -> {
                remove(item.getId());
            });
        }
        return menuService.remove(pk);
    }

    @Override
    public List<Menu> findMenuByRoleId(Long roleId) {
        if (roleId == null)
            return Collections.emptyList();
        return menuService.findByRoleId(roleId);
    }

    @Override
    public List<String> getAllPermissionVal() {
        List<Menu> menus = menuService.findAllMenu();
        return menus.stream().map(Menu::getPermissionVal).collect(Collectors.toList());
    }

    @Override
    public List<RouterVo> findRouter(Role role, String menuName) {
        List<Menu> menuList = new ArrayList<>();
        menuMap = menuService.findAllMenu().stream()
                .collect(Collectors.toMap(Menu::getId, menu -> menu));
        //超级管理员显示所有菜单
        if (Role.isAdmin(role.getRoleKey()) && role.getStatus() == 0) {
            menuList = menuService.findAllMenu();
        } else {
            menuList = menuService.findByRoleId(role.getId());
        }
        if (!StringUtils.isEmpty(menuName)) {
            //菜单名称模糊查询
            menuList = menuList.stream().filter(menu -> menu.getMenuName().contains(menuName))
                    .collect(Collectors.toList());
        }
        List<Menu> menuTreeList = this.buildTree(menuList);
        return this.buildRouter(menuTreeList,false);
    }

    @Override
    public List<Menu> getByRoleId(Long roleId) {
        List<Menu> menuList = menuService.findAllMenu();
        Set<Long> roleMenuIds = menuService.findByRoleId(roleId).stream()
                .map(Menu::getId)
                .collect(Collectors.toSet());
        menuList.forEach(menu -> menu.setIsSelect(roleMenuIds.contains(menu.getId())));

        return this.buildTree(menuList);
    }

    @Override
    public Boolean doAssign(MenuDto menuDto) {
        Role role = new Role();
        role.setRoleKey(menuDto.getRoleKey());
        role.setId(menuDto.getRoleId());
        roleService.update(role);
        //超级管理员拥有所有权限
        if (Role.isAdmin(menuDto.getRoleKey())) {
            return true;
        }
        roleMenuService.removeByRoleId(Collections.singletonList(menuDto.getRoleId()));
        menuDto.getMenuIdList().forEach(menuId -> {
            Menu menu = menuService.findByPk(menuId);
            if (menu != null) {
                roleMenuService.save(new RoleMenu(menuDto.getRoleId(), menu.getId()));
            }
        });
        return true;
    }

    @Override
    public List<Menu> findAllMenu() {
        return menuService.findAllMenu();
    }

    private List<RouterVo> buildRouter(List<Menu> menus, boolean isRootProcessed) {
        List<RouterVo> routers = new ArrayList<>();
        menus.forEach(menu -> {
            RouterVo router = new RouterVo();
            router.setPath(getRouterPath(menu));
            router.setName(getRouteName(menu));
            router.setComponent(menu.getComponent());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getStatus() == 2, menu.getFrame()));
            List<Menu> children = menu.getChildren();
            //目录
            if (Constants.CATALOG.equals(menu.getType()) && CollectionUtils.isNotEmpty(children)) {
                //基础布局 Layout
                router.setComponent(Constants.LAYOUT);
                if (!menu.getParentId().equals(0L)) {
                    router.setComponent(Constants.PARENT_VIEW);
                }
                //重定向路由
                router.setRedirect(menu.getComponent());
                router.setChildren(buildRouter(children,false));
            }
            //菜单挂在根目录下
            if (!isRootProcessed
                    && Constants.MENU.equals(menu.getType())
                    && menu.getParentId().equals(0L)) {
                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getStatus() == 2, 0));
                router.setComponent(Constants.LAYOUT);
                router.setChildren(buildRouter(Collections.singletonList(menu), true));
            }
            routers.add(router);
        });
        return routers;
    }

    private String getRouterPath(Menu menu) {
        if (menu.getParentId() == 0)
            return "/" + menu.getPath();
        Menu parent = menuMap.get(menu.getParentId());
        return getRouterPath(parent) + "/" + menu.getPath();
    }

    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     * @return 路由名称
     */
    public String getRouteName(Menu menu) {
        return StringUtils.capitalize(menu.getPath());
    }

    //使用递归方法建菜单
    public List<Menu> buildTree(List<Menu> menuList) {
        List<Menu> tree = new ArrayList<>();
        List<Long> idLists = menuList.stream().map(Menu::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(idLists)) {
            return Collections.emptyList();
        }
        menuList.forEach(item -> {
            //父级菜单
            if (!idLists.contains(item.getParentId())) {
                tree.add(getChildren(item, menuList));
            }
        });
        return tree;
    }

    public Menu getChildren(Menu menu,
                            List<Menu> menuList) {
        menu.setChildren(new ArrayList<>());
        menuList.forEach(item -> {
            if (item.getParentId().equals(menu.getId())) {
                menu.getChildren().add(getChildren(item, menuList));
            }
        });
        return menu;
    }

    /**
     * 初始化参数map
     *
     * @param model
     * @return
     */
    private Map<String, Object> initMapParam(Menu model) {
        Map<String, Object> map = new HashMap<>(4);
        Menu item = new Menu();
        BeanUtils.copyProperties(model, item);
        map.put("item", item);
        return map;
    }
}